﻿using ManageSystem.Common.Helper;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.IdentityModel.Tokens;
using System;
using ManageSystem.AuthorizationRequirement;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;

namespace ManageSystem.SetUp
{
    public static class AuthorizationSetUp
    {
        public static void AddAuthorizationSetup(this IServiceCollection services)
        {
            // 1【授权】、这个和上边的异曲同工，好处就是不用在controller中，写多个 roles 。
            // 然后这么写 [Authorize(Policy = "Admin")]
            /*            services.AddAuthorization(options =>
                        {
                            // 查看三个子系统信息的权限
                            options.AddPolicy("level1", policy => policy.RequireRole("user", "assistant", "minister", "admin").Build());
                            // 分账信息权限
                            options.AddPolicy("level2", policy => policy.RequireRole("assistant", "minister", "admin").Build());
                            // 查看所有信息
                            options.AddPolicy("level3", policy => policy.RequireRole("minister", "admin").Build());
                            // 管理员权限
                            options.AddPolicy("level4", policy => policy.RequireRole("admin").Build());


                        });*/
            var permissionRequirement = new PermissionRequirement(new List<PermissionData>());

            // add policy
            services.AddAuthorization(options =>
            {
                // 对每个用户进行“api”层次的授权
                options.AddPolicy("Permission", policy => policy.Requirements.Add(permissionRequirement));
                // 管理员权限
                options.AddPolicy("admin", policy => policy.RequireRole("admin").Build());
                // 普通用户
                options.AddPolicy("user", policy => policy.RequireRole("user").Build());
            });

            // 将权限验证的关键类注册，jwt策略模式指定为PermissionRequireMent时就会执行该类方法
            services.AddScoped<IAuthorizationHandler, PermissionHandler>();

            // 单例模式
            services.AddSingleton(permissionRequirement);

            // 用来获取httpcontext
            services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();







            if (services == null) throw new ArgumentNullException(nameof(services));

            var symmetricKeyAsBase64 = Appsettings.app(new string[] { "AppSettings", "JwtSetting", "SecretKey" });
            var keyByteArray = Encoding.ASCII.GetBytes(symmetricKeyAsBase64);
            // secret key
            var signingKey = new SymmetricSecurityKey(keyByteArray);
            var Issuer = Appsettings.app(new string[] { "AppSettings", "JwtSetting", "Issuer" });
            var Audience = Appsettings.app(new string[] { "AppSettings", "JwtSetting", "Audience" });



            // 令牌验证参数
            var tokenValidationParameters = new TokenValidationParameters
            {
                ValidateIssuerSigningKey = true,
                IssuerSigningKey = signingKey,
                ValidateIssuer = true,
                ValidIssuer = Issuer,//发行人
                ValidateAudience = true,
                ValidAudience = Audience,//订阅人
                ValidateLifetime = true,
                ClockSkew = TimeSpan.FromSeconds(30),
                RequireExpirationTime = true,
            };

            //2.1【认证】、core自带官方JWT认证
            // 开启Bearer认证
            services.AddAuthentication("Bearer")
             // 添加JwtBearer服务
             .AddJwtBearer(options =>
             {
                 options.TokenValidationParameters = tokenValidationParameters;
                 options.Events = new JwtBearerEvents
                 {
                     OnAuthenticationFailed = context =>
                     {
                         // 如果过期，则把<是否过期>添加到，返回头信息中
                         if (context.Exception.GetType() == typeof(SecurityTokenExpiredException))
                         {
                             context.Response.Headers.Add("Token-Expired", "true");
                         }
                         return Task.CompletedTask;
                     }
                 };
             });



        }
    }
}
